package com.luo.d3s.light.jpa.ec.application.service.impl;

import com.luo.d3s.core.application.dto.Response;
import com.luo.d3s.core.application.dto.SingleResponse;
import com.luo.d3s.core.util.Optionals;
import com.luo.d3s.core.util.validation.Validates;
import com.luo.d3s.light.jpa.ec.application.assembler.CategoryAssembler;
import com.luo.d3s.light.jpa.ec.application.dto.command.CategoryCreateCommand;
import com.luo.d3s.light.jpa.ec.application.dto.command.CategoryModifyCommand;
import com.luo.d3s.light.jpa.ec.application.dto.vo.CategoryVo;
import com.luo.d3s.light.jpa.ec.application.service.CategoryCommandService;
import com.luo.d3s.light.jpa.ec.application.service.CategoryQueryService;
import com.luo.d3s.light.jpa.ec.domain.base.BizId;
import com.luo.d3s.light.jpa.ec.domain.category.*;
import com.luo.d3s.light.jpa.ec.domain.service.CategorySubIdsService;
import com.luo.d3s.light.jpa.ec.domain.specification.CategorySpecification;
import com.luo.d3s.light.jpa.ec.domain.specification.GoodsNotExistInCategoriesSpecification;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 分类命令处理服务实现类
 *
 * @author luohq
 * @date 2023-01-04 17:06
 */
@Service
@CacheConfig(cacheNames = CategoryQueryService.CATEGORY_TREE_CACHE_NAME)
@CacheEvict(allEntries = true)
public class CategoryCommandServiceImpl implements CategoryCommandService {

    private CategoryRepository categoryRepository;
    private CategorySubIdsService categorySubIdsService;
    private CategorySpecification categorySpecification;
    private GoodsNotExistInCategoriesSpecification goodsNotExistInCategoriesSpecification;


    public CategoryCommandServiceImpl(CategoryRepository categoryRepository,
                                      CategorySubIdsService categorySubIdsService, CategorySpecification categorySpecification,
                                      GoodsNotExistInCategoriesSpecification goodsNotExistInCategoriesSpecification) {
        this.categoryRepository = categoryRepository;
        this.categorySubIdsService = categorySubIdsService;
        this.categorySpecification = categorySpecification;
        this.goodsNotExistInCategoriesSpecification = goodsNotExistInCategoriesSpecification;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public SingleResponse<CategoryVo> createCategory(CategoryCreateCommand categoryCreateCommand) {
        //创建分类实体
        Category category = CategoryFactory.createCategory(categoryCreateCommand);
        //验证新增分类是否合法
        this.categorySpecification.isSatisfiedBy(category);
        //保存分类
        category = this.categoryRepository.save(category);
        //转换CategoryVo
        return SingleResponse.of(CategoryAssembler.toCategoryVo(category));
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public Response modifyCategory(CategoryModifyCommand categoryModifyCommand) {
        //查询分类实体
        Category category = this.categoryRepository.findById(BizId.fromValue(categoryModifyCommand.getId())).orElse(null);
        Validates.notNull(category, "category does not exist");
        //修改基础信息
        category.modifyBasicInfo(categoryModifyCommand);
        //验证待修改分类是否合法
        this.categorySpecification.isSatisfiedBy(category);
        //保存实体
        this.categoryRepository.save(category);
        return Response.buildSuccess();
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public Response removeCategory(Long categoryId) {
        //转换分类ID
        BizId categoryEntityId = BizId.fromValue(categoryId);
        //调用领域服务查询当前分类的所有子分类ID
        List<BizId> subCategoryIdsWithParentId = this.categorySubIdsService.extractSubCategoryIds(categoryEntityId);
        //验证待删除的分类ID下不存在商品
        this.goodsNotExistInCategoriesSpecification.isSatisfiedBy(subCategoryIdsWithParentId);
        //批量删除当前分类及其子分类
        this.categoryRepository.deleteAllByIdInBatch(subCategoryIdsWithParentId);
        return Response.buildSuccess();
    }
}
